

#ifndef UD_DBINDEX_H
#define UD_DBINDEX_H

#include "zdbmain.h"

#pragma pack(push, 8)

class UcDbIndexIterator;
class UcDbFilter;
class UcDbIndexUpdateData;
class UcDbBlockChangeIterator;
class UcDbFilteredBlockIterator;
class UcDbFilter;
class UcDbImpDatabase;
class UcDbBlockTableRecord;
class UcDbBlockChangeIterator;
class UcDbIndexUpdateData;

class UcDbIndex : public UcDbObject
{
public:
    UCDB_DECLARE_MEMBERS(UcDbIndex);

    UcDbIndex();
    virtual ~UcDbIndex();

    virtual UcDbFilteredBlockIterator* 
                  newIterator(const UcDbFilter* pFilter) const;

    virtual Ucad::ErrorStatus rebuildFull(UcDbIndexUpdateData* pIdxData);
 
    virtual UcDbObjectId objectBeingIndexedId()  const;

    void           setLastUpdatedAt(const UcDbDate& time);
    UcDbDate       lastUpdatedAt() const;

    void           setLastUpdatedAtU(const UcDbDate& time);
    UcDbDate       lastUpdatedAtU() const;

    ZSoft::Boolean isUptoDate   () const;  

protected:

    virtual Ucad::ErrorStatus rebuildModified(UcDbBlockChangeIterator* iter);

    friend class UcDbImpIndex;
    friend Ucad::ErrorStatus processBTRIndexObjects(
                                   UcDbBlockTableRecord* pBTR,
                                   int indexCtlVal,
                                   UcDbBlockChangeIterator* pBlkChgIter,
                                   UcDbIndexUpdateData*     pIdxUpdData);
};

class UcDbFilteredBlockIterator
{
public:
    UcDbFilteredBlockIterator()          {}
    virtual ~UcDbFilteredBlockIterator() {}

    virtual Ucad::ErrorStatus start()               = 0;
    virtual UcDbObjectId      next()                = 0;
    virtual UcDbObjectId      id() const            = 0;
    virtual Ucad::ErrorStatus seek(UcDbObjectId id) = 0;

    virtual double estimatedHitFraction() const             = 0;
    virtual Ucad::ErrorStatus accepts(UcDbObjectId id, 
                      ZSoft::Boolean& idPassesFilter) const = 0;

    virtual ZSoft::Boolean    buffersForComposition() const;
    virtual Ucad::ErrorStatus addToBuffer(UcDbObjectId id);
};

class UcDbCompositeFilteredBlockIterator
{
private:
    UcDbCompositeFilteredBlockIterator(
        const UcDbCompositeFilteredBlockIterator& copyFrom);

protected:
    UcDbCompositeFilteredBlockIterator() {}

public:
    virtual ~UcDbCompositeFilteredBlockIterator() {}

    virtual Ucad::ErrorStatus init(UcDbFilter* const * ppFilters,
                                   int numFilters,
                                   const UcDbBlockTableRecord* pBtr) = 0;

    virtual Ucad::ErrorStatus start()    = 0;
    virtual UcDbObjectId      next()     = 0;
    virtual UcDbObjectId      id() const = 0;

    virtual Ucad::ErrorStatus seek(UcDbObjectId id)  = 0;
    static UcDbCompositeFilteredBlockIterator* newIterator();
};

class UcDbBlockTableRecord;
class UcDbBlockReference;

namespace UcDbIndexFilterManager
{

    Ucad::ErrorStatus updateIndexes(UcDbDatabase* pDb);

    Ucad::ErrorStatus addIndex    (UcDbBlockTableRecord* pBTR,
                                   UcDbIndex*            pIndex);

    Ucad::ErrorStatus removeIndex (UcDbBlockTableRecord* pBTR, 
                                   const UcRxClass*      key);

    Ucad::ErrorStatus getIndex(const UcDbBlockTableRecord* pBTR,
                               const UcRxClass* key, 
                               UcDb::OpenMode readOrWrite,
                               UcDbIndex*& pIndex);

    Ucad::ErrorStatus getIndex(const UcDbBlockTableRecord* pBTR,
                               int index,
                               UcDb::OpenMode readOrWrite,
                               UcDbIndex*& pIndex);

    int numIndexes(const UcDbBlockTableRecord* pBtr);

    Ucad::ErrorStatus addFilter(UcDbBlockReference* pBlkRef,
                                UcDbFilter*         pFilter);

    Ucad::ErrorStatus removeFilter(UcDbBlockReference* pBlkRef,
                                   const UcRxClass*    key);

    Ucad::ErrorStatus getFilter(const UcDbBlockReference* pRef,
                                const UcRxClass*          key,       
                                UcDb::OpenMode readOrWrite,
                                UcDbFilter*&   pFilter);
    
    Ucad::ErrorStatus getFilter(const UcDbBlockReference* pRef,
                                int index,
                                UcDb::OpenMode readOrWrite,
                                UcDbFilter*& pFilter);

    int  numFilters(const UcDbBlockReference* pBlkRef);
};

class UcDbHandleTable;
class UcDbHandleTableIterator;

class UcDbIndexUpdateData 
{
    public:
        
        enum UpdateFlags 
        {                      
            kModified   = 1,   
            kDeleted    = 2,

            kProcessed  = 4,   
            kUnknownKey = 8

        };
        
        Ucad::ErrorStatus addId      (UcDbObjectId id);

        Ucad::ErrorStatus setIdFlags (UcDbObjectId id, ZSoft::UInt8 flags);
        
        Ucad::ErrorStatus setIdData  (UcDbObjectId id, ZSoft::ULongPtr data);
        
        Ucad::ErrorStatus getIdData       (UcDbObjectId id, ZSoft::ULongPtr& data)  const;
        Ucad::ErrorStatus getIdFlags      (UcDbObjectId id, ZSoft::UInt8&  flags) const;       
        Ucad::ErrorStatus getFlagsAndData (UcDbObjectId   id, 
                                           ZSoft::UInt8&  flags, 
                                           ZSoft::ULongPtr& data) const;

    private:
        UcDbIndexUpdateData();
        ~UcDbIndexUpdateData();

        UcDbIndexUpdateData(const UcDbIndexUpdateData&);

        UcDbHandleTable* mpTable;

        friend class UcDbIndexUpdateDataIterator;
        friend class UcDbImpDatabase;
};

class UcDbIndexUpdateDataIterator
{
    public:
        UcDbIndexUpdateDataIterator  (const UcDbIndexUpdateData* p);
        ~UcDbIndexUpdateDataIterator ();

        void start   ();
        void next    ();
        bool done    ();

        Ucad::ErrorStatus currentData (UcDbObjectId&  id, 
                                       ZSoft::UInt8&  flags, 
                                       ZSoft::ULongPtr& data) const;
 
    private:
        UcDbHandleTableIterator* mpIter;
};

class UcDbBlockChangeIterator
{
private:
    UcDbBlockChangeIterator();
    UcDbBlockChangeIterator(const UcDbBlockChangeIterator&);

    UcDbBlockChangeIterator (UcDbObjectId         btrId,
                             UcDbIndexUpdateData* pIdxUpdData);
    ~UcDbBlockChangeIterator();
    
public:
    void         start ();
    UcDbObjectId id    () const;
    void         next  ();
    bool         done  ();

    Ucad::ErrorStatus    curIdInfo    (UcDbObjectId&  id,
                                       ZSoft::UInt8&  flags, 
                                       ZSoft::ULongPtr& data) const;

    Ucad::ErrorStatus    setCurIdInfo (ZSoft::UInt8   flags,  
                                       ZSoft::ULongPtr data);

    UcDbIndexUpdateData* updateData () const;

    void clearProcessedFlags();

private:
    UcDbIndexUpdateData*         mpIds;
    UcDbObjectId                 mBTRId;

    UcDbIndexUpdateDataIterator* mpIter;

    friend class UcDbImpDatabase;
};


#pragma pack(pop)

#endif 
